package com.koron.operation.classes.form.service.impl;


import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.ObjectUtil;
import com.alibaba.fastjson.JSONObject;
import com.github.pagehelper.PageInfo;
import com.koron.bean.base.BaseBean;
import com.koron.bean.base.Response;
import com.koron.bean.query.PageQuery;
import com.koron.bean.system.post.po.PostUserPo;
import com.koron.bean.system.post.query.PostUserQuery;
import com.koron.bean.system.post.vo.PostUserVo;
import com.koron.bean.system.staff.po.AppUserPo;
import com.koron.common.core.business.common.mapper.StaffMapper;
import com.koron.common.core.business.configsettings.utils.ConfigInfoTool;
import com.koron.common.core.business.system.feign.SystemFeignService;
import com.koron.operation.classes.form.bean.constants.ClassesFormUtil;
import com.koron.operation.classes.form.bean.constants.DateDuration;
import com.koron.operation.classes.form.bean.convertor.ClassesFormConvertor;
import com.koron.operation.classes.form.bean.dto.*;
import com.koron.operation.classes.form.bean.po.*;
import com.koron.operation.classes.form.bean.query.ClassesFormQuery;
import com.koron.operation.classes.form.bean.query.ClassesFormShiftQuery;
import com.koron.operation.classes.form.bean.vo.ClassesFormChangeVO;
import com.koron.operation.classes.form.bean.vo.ClassesFormVO;
import com.koron.operation.classes.form.mapper.ClassesFormMapper;
import com.koron.operation.classes.form.service.*;
import com.koron.operation.classes.info.bean.dto.ClassesClassifyDTO;
import com.koron.operation.classes.info.bean.po.ClassesClassifyItem;
import com.koron.operation.classes.info.service.ClassesClassifyService;
import com.koron.operation.classes.schedule.bean.dto.ClassesShiftDTO;
import com.koron.operation.classes.schedule.bean.po.ClassesStaff;
import com.koron.operation.classes.shift.bean.dto.ChangeShiftDTO;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import org.koron.ebs.mybatis.SessionFactory;
import org.koron.ebs.mybatis.TaskAnnotation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;

/**
 * 月度排班表(ClassesForm)表服务实现类
 *
 * @author jzp
 * @since 2023-05-17 09:43:29
 */
@Service
@RequiredArgsConstructor
public class ClassesFormServiceImpl implements ClassesFormService {

    private final ClassesClassifyService classesClassifyService;
    private final ClassesFormRowService classesFormRowService;
    private final ClassesFormShiftService classesFormShiftService;
    private final ClassesFormRecordService classesFormRecordService;
    private final ClassesFormChangeService classesFormChangeService;
    private final ClassesFormTakeoverService classesFormTakeoverService;
    private final SystemFeignService systemFeignService;
    private final ClassesFormRankService classesFormRankService;

    @Autowired
    private ClassesFormConvertor classesFormConvertor;

    /**
     * 通过ID查询单条数据
     */
    @Override
    @TaskAnnotation("getById")
    public ClassesForm getById(SessionFactory factory, String id) {
        ClassesFormMapper mapper = factory.getMapper(ClassesFormMapper.class);
        return mapper.selectById(id);
    }

    @Override
    @TaskAnnotation("getDtoById")
    public ClassesFormDTO getDtoById(SessionFactory factory, String id) {
        ClassesFormMapper mapper = factory.getMapper(ClassesFormMapper.class);
        ClassesFormDTO classesFormDTO = mapper.selectDtoById(id);
        if (classesFormDTO == null) {
            return null;
        }
        // 查询对应的排班方案
        ClassesClassifyDTO classesClassifyDTO = classesClassifyService.getDtoById(factory, classesFormDTO.getClassesId());
        List<ClassesClassifyItem> items = classesClassifyDTO.getItems();
        Map<String, ClassesClassifyItem> classesItemMap = items.stream().collect(Collectors.toMap(BaseBean::getId, e -> e));

        // 查询对应的变更信息
        List<ClassesFormChangeVO> classesFormChangeVOS = classesFormChangeService.listByFormId(factory, id);
        Map<String, List<ClassesFormChangeVO>> changeMap = Optional.of(classesFormChangeVOS).map(e -> e.stream().collect(Collectors.groupingBy(ClassesFormChangeVO::getShiftId))).orElse(new HashMap<>());

        // 查询对应的接班人信息
        List<ClassesFormTakeover> classesFormTakeovers = classesFormTakeoverService.listByFormId(factory, id);
        Map<String, List<ClassesFormTakeover>> takeoverMap = Optional.of(classesFormTakeovers).map(e -> e.stream().collect(Collectors.groupingBy(ClassesFormTakeover::getShiftIdAfter))).orElse(new HashMap<>());

        // 计算ClassesFormShiftDTO
        if (classesFormDTO.getRowList() != null) {
            classesFormDTO.getRowList().stream()
                    .map(ClassesFormRowDTO::getShiftList)
                    .flatMap(Collection::stream)
                    .forEach(c -> {
                        // 填充changeList和takeoverList
                        c.setChangeList(changeMap.get(c.getId()));
                        c.setTakeoverList(takeoverMap.get(c.getId()));

                        // 计算工时
                        // 1. 计划工时
                        String classesId = c.getClassesItemId();
                        if (classesId == null) {
                            return;
                        }
                        ClassesClassifyItem classesClassifyItem = classesItemMap.get(classesId);
                        Assert.notNull(classesClassifyItem, "找不到班次：" + c.getClassesItemName());
                        double planHours = NumberUtil.parseDouble(classesClassifyItem.getDuration()) - NumberUtil.parseDouble(classesClassifyItem.getOverDuration());
                        c.setPlanHours(planHours);

                        // 2. 加班工时
                        // 2.1. 原始加班工时
                        double overOriginal = NumberUtil.parseDouble(classesClassifyItem.getOverDuration());
                        // 2.2. 调班工时
                        double overChange = 0.0;
                        if (c.getChangeList() != null || c.getTakeoverList() != null) {
                            Date classesStartTimeAfter0 = null;
                            Date classesEndTimeAfter0 = null;
                            Date createTime0 = null;
                            Date classesStartTimeAfter123 = null;
                            Date classesEndTimeAfter123 = null;
                            Date createTime123 = null;
                            String changeType = "";
                            String itemIdAfter = "";
                            // true为加班。false为其他
                            if (c.getChangeList() != null) {
                                Map<Boolean, List<ClassesFormChangeVO>> formChangeTypeMap = c.getChangeList().stream().collect(Collectors.partitioningBy(e -> "0".equals(e.getChangeType())));

                                // 加班
                                List<ClassesFormChangeVO> classesFormChanges0 = formChangeTypeMap.get(true);
                                if (classesFormChanges0 != null && classesFormChanges0.size() != 0) {
                                    ClassesFormChange classesFormChange = classesFormChanges0.get(classesFormChanges0.size() - 1);
                                    classesStartTimeAfter0 = classesFormChange.getClassesStartTimeAfter();
                                    classesEndTimeAfter0 = classesFormChange.getClassesEndTimeAfter();
                                    createTime0 = classesFormChange.getCreateTime();
                                }
                                // 其他
                                List<ClassesFormChangeVO> classesFormChanges123 = formChangeTypeMap.get(false);
                                if (classesFormChanges123 != null && classesFormChanges123.size() != 0) {
                                    ClassesFormChange classesFormChange = classesFormChanges123.get(classesFormChanges123.size() - 1);
                                    classesStartTimeAfter123 = classesFormChange.getClassesStartTimeAfter();
                                    classesEndTimeAfter123 = classesFormChange.getClassesEndTimeAfter();
                                    createTime123 = classesFormChange.getCreateTime();
                                    changeType = classesFormChange.getChangeType();
                                    itemIdAfter = classesFormChange.getClassesItemIdAfter();
                                }
                            }
                            if (c.getTakeoverList() != null) {
                                Map<Boolean, List<ClassesFormTakeover>> takeoverChangeTypeMap = c.getTakeoverList().stream().collect(Collectors.partitioningBy(e -> "0".equals(e.getChangeType())));
                                // 加班
                                List<ClassesFormTakeover> classesFormTakeovers0 = takeoverChangeTypeMap.get(true);
                                if (classesFormTakeovers0 != null && classesFormTakeovers0.size() != 0) {
                                    ClassesFormTakeover classesFormTakeover = classesFormTakeovers0.get(classesFormTakeovers0.size() - 1);
                                    if (createTime0 == null || classesFormTakeover.getCreateTime().after(createTime0)) {
                                        classesStartTimeAfter0 = classesFormTakeover.getClassesStartTimeAfter();
                                        classesEndTimeAfter0 = classesFormTakeover.getClassesEndTimeAfter();
                                    }
                                }
                                // 其他
                                List<ClassesFormTakeover> classesFormTakeovers123 = takeoverChangeTypeMap.get(false);
                                if (classesFormTakeovers123 != null && classesFormTakeovers123.size() != 0) {
                                    ClassesFormTakeover classesFormTakeover = classesFormTakeovers123.get(classesFormTakeovers123.size() - 1);
                                    if (createTime123 == null || classesFormTakeover.getCreateTime().after(createTime123)) {
                                        classesStartTimeAfter123 = classesFormTakeover.getClassesStartTimeAfter();
                                        classesEndTimeAfter123 = classesFormTakeover.getClassesEndTimeAfter();
                                        changeType = classesFormTakeover.getChangeType();
                                        itemIdAfter = classesFormTakeover.getClassesItemIdAfter();
                                    }
                                }
                            }
                            // 加班
                            String duration0 = ClassesFormUtil.betweenHour(classesStartTimeAfter0, classesEndTimeAfter0);
                            overChange += NumberUtil.parseDouble(duration0);

                            double duration123 = NumberUtil.parseDouble(ClassesFormUtil.betweenHour(classesStartTimeAfter123, classesEndTimeAfter123));
                            // 休假
                            if ("1".equals(changeType)) {
                                // 减去加班工时
                                overOriginal -= duration123;
                            }
                            // 调班
                            else if ("3".equals(changeType)) {
                                ClassesClassifyItem classesClassifyItemAfter = classesItemMap.get(itemIdAfter);
                                double overAfter = NumberUtil.parseDouble(classesClassifyItemAfter.getDuration()) - NumberUtil.parseDouble(classesClassifyItemAfter.getOverDuration());
                                // 新的加班工时 = 调班后的加班工时-原始加班工时
                                overOriginal += overAfter - overOriginal;
                            }
                        }
                        c.setOverHours(overOriginal + overChange);
                    });
        }

        return classesFormDTO;
    }

    @Override
    @TaskAnnotation("getCurr")
    public ClassesForm getCurr(SessionFactory factory, String deptId, Date date) {
        ClassesFormQuery classesFormQuery = new ClassesFormQuery();
        classesFormQuery.setDeptId(deptId);
        classesFormQuery.setShiftTime(DateUtil.parse(DateUtil.formatDate(date), "yyyy-MM"));
        List<ClassesFormVO> list = list(factory, classesFormQuery);
        if (list == null || list.size() == 0) {
            return null;
        }
        return list.get(list.size() - 1);
    }

    @Override
    @TaskAnnotation("getCurrDto")
    public ClassesFormDTO getCurrDto(SessionFactory factory, String deptId, Date date) {
        ClassesForm currForm = getCurr(factory, deptId, date);
        return getDtoById(factory, currForm.getId());
    }

    @Override
    @TaskAnnotation("getUserListByOrgId")
    @SneakyThrows
    public List<ClassesFormRankDTO> getUserListByOrgId(SessionFactory factory, String orgId) {
        // 1. 从写死的json文件中查
        Map<String, String> config = ConfigInfoTool.getConfigByCode("operation", "operation_shift");
        if (!"1".equals(config.get("postInfoIsFromTable"))) {
            String path = "json/user.json";
            ClassPathResource classPathResource = new ClassPathResource(path);
            String jsonStr = IoUtil.read(classPathResource.getInputStream(), StandardCharsets.UTF_8);
            JSONObject jsonObject = JSONObject.parseObject(jsonStr);
            String o = jsonObject.getString(orgId);
            return JSONObject.parseArray(o, ClassesFormRankDTO.class);
        }

        // 2. 查排班职级人员配置中查
        String waterDbEnv = factory.getDbEnv();
        ClassesFormRank classesFormRank = new ClassesFormRank();
        classesFormRank.setDeptId(orgId);
        List<ClassesFormRankDTO> result = classesFormRankService.listDto(factory, classesFormRank);
        if (CollUtil.isNotEmpty(result)) {
            return result;
        }

        // 3. 从系统管理岗位为人员中查
        factory.setDbEnv(null);
        // 查询当前组织的所有岗位
        PostUserQuery postUserQuery = new PostUserQuery();
        postUserQuery.setOrgId(orgId);
        Response<List<PostUserVo>> listResponse =
                systemFeignService.queryPostList(postUserQuery);
        List<PostUserVo> postUserVoList = listResponse.getData();
        // 通过岗位进行分组
        if (postUserVoList == null) {
            return null;
        }
        List<String> userAccountList = postUserVoList.stream().map(PostUserPo::getUserAccount).collect(Collectors.toList());
        StaffMapper mapper = factory.getMapper(StaffMapper.class);
        List<AppUserPo> appUserPos = mapper.selectUserListByIds(userAccountList);
        Map<String, AppUserPo> userMap = appUserPos.stream().collect(Collectors.toMap(AppUserPo::getAccount, e -> e, (o1, o2) -> o1));

        Map<String, List<PostUserVo>> postUserMap = postUserVoList.stream().collect(Collectors.groupingBy(PostUserVo::getPostId));
        Map<String, PostUserVo> postMap = postUserVoList.stream().collect(Collectors.toMap(PostUserVo::getPostId, e -> e, (o1, o2) -> o1));

        postUserMap.forEach((k,v) -> {
            List<ClassesFormUser> users = v.stream().map(e -> {
                AppUserPo appUserPo = userMap.get(e.getUserAccount());
                return new ClassesFormUser(appUserPo.getAccount(), appUserPo.getUserName(), appUserPo.getUserPinyin());
            }).collect(Collectors.toList());
            PostUserVo post = postMap.get(k);
            ClassesFormRankDTO amdRankDTO = new ClassesFormRankDTO(post.getId(), post.getPostName(), post.getPostPinyin(), users);
            result.add(amdRankDTO);
        });
        // 还原env
        factory.setDbEnv(waterDbEnv);
        Assert.notEmpty(result, "未找到相关排班职级人员数据！");
        return result;
    }

    /**
     * 查询所有数据
     */
    @Override
    @TaskAnnotation("list")
    public List<ClassesFormVO> list(SessionFactory factory, ClassesFormQuery query) {
        ClassesFormMapper mapper = factory.getMapper(ClassesFormMapper.class);
        return mapper.selectList(query);
    }

    @Override
    @TaskAnnotation("page")
    public PageInfo<ClassesFormVO> page(SessionFactory factory, PageQuery pageQuery, ClassesFormQuery query) {
        pageQuery.unPrefixOrders("classesForm", Arrays.asList("currNodeCode",
                "currNodeName",
                "currNodeUserId",
                "currNodeUserName"
                ));
        return ClassesFormService.super.page(factory, pageQuery, query);
    }

    @Override
    @TaskAnnotation("info")
    public ClassesFormClockIn info(SessionFactory factory, String deptId, String account, Date date) {
        ClassesForm currForm = this.getCurr(factory, deptId, date);
        if (currForm == null) {
            return null;
        }
        ClassesFormShiftQuery query = new ClassesFormShiftQuery();
        query.setFormId(currForm.getId());
        query.setUserId(account);
        query.setShiftDate(date);
        List<ClassesFormShift> shiftList = classesFormShiftService.list(factory, query);
        if (shiftList == null || shiftList.size() == 0) {
            return null;
        }

        // 查询当前班次
        ClassesFormShift currShift = shiftList.get(shiftList.size() - 1);
        if (currShift == null || currShift.getShiftDate() == null) {
            return null;
        }
        ClassesFormRecordDTO classesFormRecordDTO = classesFormConvertor.entityToFormRecordDTO(currShift);

        // 查询当前班次的打卡记录
        ClassesFormRecord classesFormRecord = new ClassesFormRecord();
        classesFormRecord.setShiftId(classesFormRecordDTO.getId());
        List<ClassesFormRecord> recordList = classesFormRecordService.list(factory, classesFormRecord);

        // 构建数据
        ClassesFormClockIn classesFormClockIn = new ClassesFormClockIn();
        classesFormClockIn.setRankId(currShift.getRankId());
        classesFormClockIn.setRankName(currShift.getRankName());
        classesFormClockIn.setRankPinyin(currShift.getRankPinyin());
        classesFormClockIn.setUserId(currShift.getUserId());
        classesFormClockIn.setUserName(currShift.getUserName());
        classesFormClockIn.setUserPinyin(currShift.getUserPinyin());
        classesFormClockIn.setDeptId(currForm.getDeptId());
        classesFormClockIn.setDeptName(currForm.getDeptName());
        classesFormClockIn.setShiftDate(date);

        // 上班面板
        ClassesFormRecordDTO beforeClockIn = BeanUtil.toBean(classesFormRecordDTO, ClassesFormRecordDTO.class);
        classesFormClockIn.setBeforeClockIn(beforeClockIn);
        // 下班面板
        ClassesFormRecordDTO afterClockIn = BeanUtil.toBean(classesFormRecordDTO, ClassesFormRecordDTO.class);
        classesFormClockIn.setAfterClockIn(afterClockIn);

        // 打卡记录
        if (recordList == null || recordList.size() == 0) {
            return classesFormClockIn;
        }
        // 0上班卡 1下班卡
        Map<Boolean, List<ClassesFormRecord>> map = recordList.stream().collect(Collectors.partitioningBy(e -> Objects.equals(e.getClockType(), "0")));
        beforeClockIn.setRecordList(map.get(true));
        afterClockIn.setRecordList(map.get(false));
        return classesFormClockIn;
    }

    @Override
    @TaskAnnotation("shiftInfo")
    public ChangeShiftDTO shiftInfo(SessionFactory factory, String deptId, String rankId, Date date) {
        ChangeShiftDTO changeShiftDTO = null;
        // 找到当前值班人员
        ClassesFormDTO currFormDto = this.getCurrDto(factory, deptId, date);
        if (currFormDto == null || currFormDto.getRowList() == null) {
            return null;
        }
        ClassesFormShiftDTO dto = currFormDto.getRowList().stream()
                .filter(e -> Objects.equals(e.getRankId(), rankId))
                .map(ClassesFormRowDTO::getShiftList)
                .flatMap(Collection::stream)
                .filter(e -> {
                    List<DateDuration> dutyTime = e.getDutyTime();
                    if (dutyTime == null) {
                        return false;
                    }
                    for (DateDuration dateDuration : dutyTime) {
                        if (ObjectUtil.hasNull(date, dateDuration.getStartTime(), dateDuration.getEndTime())) {
                            continue;
                        }
                        if (DateUtil.isIn(date, dateDuration.getStartTime(), dateDuration.getEndTime())) {
                            return true;
                        }
                    }
                    return false;
                })
                .findFirst()
                .orElse(null);
        if (dto != null) {
            changeShiftDTO = new ChangeShiftDTO();
            ClassesShiftDTO thisClassesShift = new ClassesShiftDTO();
            changeShiftDTO.setThisClassesShift(thisClassesShift);
            ClassesStaff classesStaff = new ClassesStaff();
            classesStaff.setStaffBy(dto.getUserId());
            classesStaff.setStaffName(dto.getUserName());
            thisClassesShift.setStaffs(Collections.singletonList(classesStaff));
        }
        return changeShiftDTO;
    }

    /**
     * 新增数据
     */
    @Override
    @TaskAnnotation("save")
    public boolean save(SessionFactory factory, ClassesForm classesForm) {
        if (classesForm.getStatus() == null) {
            classesForm.setStatus(ClassesFormUtil.Status.DRAFT);
        }
        checkDuplicated(factory, classesForm);
        ClassesFormMapper mapper = factory.getMapper(ClassesFormMapper.class);
        return mapper.insertOrUpdate(classesForm) > 0;
    }

    private void checkDuplicated(SessionFactory factory, ClassesForm classesForm) {
        ClassesFormQuery query = new ClassesFormQuery();
        query.setDeptId(classesForm.getDeptId());
        query.setShiftTime(classesForm.getShiftTime());
        List<ClassesFormVO> list = list(factory, query);
        if (classesForm.getId() == null) {
            Assert.state(list == null || list.size() == 0, "同一个单位不能重复创建排班表");
        } else {
            Assert.state(list == null || list.size() <= 1, "同一个单位不能重复创建排班表");
        }
    }

    @Override
    @TaskAnnotation("saveDto")
    public boolean saveDto(SessionFactory factory, ClassesFormDTO classesFormDTO) {
        // 1. 保存基本信息
        this.save(factory, classesFormDTO);

        // 2. 清楚原数据
        classesFormRowService.removeByFormId(factory, classesFormDTO.getId());
        classesFormShiftService.removeByFormId(factory, classesFormDTO.getId());

        // 3. 保存职级信息
        List<ClassesFormRowDTO> formRowList = classesFormDTO.getRowList();
        if (CollUtil.isEmpty(formRowList)) {
            return true;
        }
        AtomicInteger rankSort = new AtomicInteger();
        formRowList.forEach(rank -> {
            rank.setFormId(classesFormDTO.getId());
            rank.setSort(rankSort.getAndIncrement());
        });
        classesFormRowService.saveBatch(factory, formRowList);

        // 4. 保存单元格信息
        List<ClassesFormShift> shiftList = new ArrayList<>();
        for (ClassesFormRowDTO classesFormRowDTO : formRowList) {
            List<ClassesFormShiftDTO> classesFormShiftList = classesFormRowDTO.getShiftList();
            if (CollUtil.isEmpty(classesFormShiftList)) {
                continue;
            }
            AtomicInteger shiftSort = new AtomicInteger();
            classesFormShiftList.forEach(shift -> {
                classesFormConvertor.rowFillShift(classesFormRowDTO, shift);
                shift.setSort(shiftSort.getAndIncrement());
                shift.setClassesId(classesFormDTO.getClassesId());
            });
            shiftList.addAll(classesFormShiftList);
        }
        classesFormShiftService.saveBatch(factory, shiftList);
        return true;
    }

    /**
     * 修改数据
     */
    @Override
    @TaskAnnotation("update")
    public boolean update(SessionFactory factory, ClassesForm classesForm) {
        ClassesFormMapper mapper = factory.getMapper(ClassesFormMapper.class);
        return mapper.update(classesForm) > 0;
    }

    @Override
    @TaskAnnotation("updateStatus")
    public boolean updateStatus(SessionFactory factory, String id, String status) {
        ClassesForm classesForm = new ClassesForm();
        classesForm.setId(id);
        classesForm.setStatus(status);
        return update(factory, classesForm);
    }

    @Override
    @TaskAnnotation("submit")
    public boolean submit(SessionFactory factory, ClassesFormDTO classesFormDTO, String currNodeCode) {
        // 草稿
        if (currNodeCode == null || currNodeCode.contains("draft-") || currNodeCode.contains(ClassesFormUtil.Status.DRAFT)) {
            return updateStatus(factory, classesFormDTO.getId(), ClassesFormUtil.Status.DRAFT);
        }
        // 待审核
        else if (currNodeCode.contains("call-") || currNodeCode.contains(ClassesFormUtil.Status.WAIT_REVIEW)) {
            return updateStatus(factory, classesFormDTO.getId(), ClassesFormUtil.Status.WAIT_REVIEW);
        }
        // 已归档
        else if (currNodeCode.equals("END") || currNodeCode.contains(ClassesFormUtil.Status.ARCHIVED)) {
            return updateStatus(factory, classesFormDTO.getId(), ClassesFormUtil.Status.ARCHIVED);
        }
        return false;
    }

    /**
     * 通过主键删除数据
     */
    @Override
    @TaskAnnotation("deleteById")
    public boolean deleteById(SessionFactory factory, String id) {
        ClassesFormMapper mapper = factory.getMapper(ClassesFormMapper.class);
        return mapper.hidden(id) > 0;
    }
}
